﻿using System;
using ACompany.OrderProcessing.Infrastructure;
using ACompany.OrderProcessing.Model;
using ACompany.OrderProcessing.Presentation;
using ACompany.OrderProcessing.Presentation.Product;
using ACompany.OrderProcessing.Services;
using System.Text;
using StructureMap;

public class ProductPresenter
{
    private readonly IProductDetailView _view;
    private readonly IProductService _productService;
    private Product _selectedProduct;
    private Mode _mode;
    
    public ProductPresenter(IProductDetailView View)
        : this(View, ObjectFactory.GetInstance<IProductService>())
    {
    }

    public ProductPresenter(IProductDetailView View, IProductService ProductService)
    {
        this._view = View;
        this._productService = ProductService;
    }


    public void Display()
    {
        Product Product = GetSelectedProduct();

        clearInfoAndErrorMessages();
        setButtonText();
        setTitleText();

        if (Product == null)
        {
            _view.ErrorMessage(string.Format("Could not find details from Product with Id of {0}.", _view.ProductId));
        }
        else
        {
            UpdateView(Product);
        }
    }

    private void setButtonText()
    {
        if (_mode == Mode.Add)
        {
            _view.SaveButtonText = "Add Product";
        }
        else
        {
            _view.SaveButtonText = "Save Product";
        }
    }

    private void setTitleText()
    {
        if (_mode == Mode.Add)
        {
            _view.ViewTitle("Add Product");
        }
        else
        {
            _view.ViewTitle("Edit Product");
        }
    }

    private void clearInfoAndErrorMessages()
    {
        _view.ErrorMessage(string.Empty);
        _view.InfoMessage(string.Empty);
    }

    private Product GetSelectedProduct()
    {

        if (_selectedProduct == null)
        {
            if (_view.ProductId == Guid.Empty)
            {
                // Add mode
                _selectedProduct = new Product();
                _mode = Mode.Add;
            }
            else
            {
                // Edit mode
                _selectedProduct = this._productService.FindBy(_view.ProductId);
                _mode = Mode.Edit;
            }
        }

        return _selectedProduct;

    }


    private void UpdateView(Product SelectedProduct)
    {
        _view.Name = SelectedProduct.Name;
        _view.Price = SelectedProduct.Price;
        _view.Stock = SelectedProduct.Stock;
    }


    public void SaveProduct()
    {
        Product Product = GetSelectedProduct();

        UpdateFromView(Product);
        clearInfoAndErrorMessages();

        if (Product.GetBrokenRules().Count == 0)
        {
            try
            {
                this._productService.Save(Product);

                if (_mode == Mode.Add)
                {
                    this._view.InfoMessage(string.Format("Product '{0}' has been added", Product.Name));
                    ClearView();
                }
                else
                {
                    this._view.InfoMessage("Product has been saved");
                }


            }
            catch (Exception ex)
            {
                string exceptionMessage = string.Format("A problem occurred while saving Product '{0}'. {1}{2}", Product.Name, Environment.NewLine, ex.Message);
                _view.ErrorMessage(exceptionMessage);

            }
        }
        else
        {
            DisplayErrorsIn(Product);
        }

    }

    private void UpdateFromView(Product Product)
    {
        Product.Name = _view.Name;
        Product.Price = _view.Price;
        Product.Stock = _view.Stock;
    }

    private void ClearView()
    {
        _view.Name = string.Empty;
        _view.Stock = 0;
        _view.Price = 0;
    }


    private void DisplayErrorsIn(Product Product)
    {
        StringBuilder sb = new StringBuilder();

        sb.Append("There were some problems when trying to save this Product:");
        sb.Append(Environment.NewLine);
        sb.Append(Environment.NewLine);

        foreach (BrokenRule BrokenRule in Product.GetBrokenRules())
        {
            sb.Append(BrokenRule.Rule);
            sb.Append(Environment.NewLine);
        }

        _view.ErrorMessage(sb.ToString());
    }
}